package alogcore

import (
	"os"
	"time"

	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
)

// NewLogger create logger type
func NewLogger(filePath string, level zapcore.Level, maxSize int, maxBackup int, maxAge int, compress bool, stdout bool,
	encoder string, opt ...Option,
) *zap.Logger {
	core := newZapCore(filePath, level, maxSize, maxBackup, maxAge, compress, stdout, encoder)

	zapOpt := []zap.Option{}
	for _, o := range opt {
		zapOpt = append(zapOpt, o.zapOption)
	}

	return zap.New(core,
		append(
			zapOpt,
			zap.AddCaller(),
			zap.Development(),
			zap.AddCallerSkip(2),
		)...,
	)
}

func newZapCore(filePath string, level zapcore.Level, maxSize int, maxBackup int, maxAge int, compress bool, stdout bool, encoderValue string) zapcore.Core {
	logRoll := lumberjack.Logger{
		Filename:   filePath,
		MaxSize:    maxSize,
		MaxAge:     maxAge,
		MaxBackups: maxBackup,
		Compress:   compress,
		LocalTime:  true,
	}
	atomicLevel := zap.NewAtomicLevel()
	atomicLevel.SetLevel(level)
	zapEncoder := zapcore.EncoderConfig{
		MessageKey:     "msg",
		LevelKey:       "level",
		TimeKey:        "time",
		NameKey:        "logger",
		CallerKey:      "lineNume",
		StacktraceKey:  "Alitrace",
		LineEnding:     zapcore.DefaultLineEnding,
		EncodeLevel:    zapcore.LowercaseLevelEncoder,
		EncodeTime:     zapcore.ISO8601TimeEncoder,
		EncodeDuration: zapcore.SecondsDurationEncoder,
		EncodeCaller:   zapcore.FullCallerEncoder,
		EncodeName:     zapcore.FullNameEncoder,
	}
	writeSyncer := make([]zapcore.WriteSyncer, 0, 2)
	if stdout {
		writeSyncer = append(writeSyncer, zapcore.AddSync(os.Stdout))
		if filePath != "" {
			writeSyncer = append(writeSyncer, zapcore.AddSync(&logRoll))
		}
	} else {
		writeSyncer = append(writeSyncer, zapcore.AddSync(&logRoll))
	}

	var encoder zapcore.Encoder
	switch encoderValue {
	case AlogEncoderConsole:
		zapEncoder.EncodeLevel = zapcore.CapitalLevelEncoder
		zapEncoder.EncodeTime = func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
			enc.AppendString(t.Format("2006-01-02 15:04:05.000"))
		}
		encoder = zapcore.NewConsoleEncoder(zapEncoder)
	case AlogEncoderJson:
		fallthrough
	default:
		encoder = zapcore.NewJSONEncoder(zapEncoder)
	}

	return zapcore.NewCore(
		encoder,
		zapcore.NewMultiWriteSyncer(writeSyncer...),
		atomicLevel,
	)
}
